local unpack = unpack or table.unpack
local capabilities = require("cmp_nvim_lsp").default_capabilities()
local map = vim.keymap.set
local lspconfig = require("lspconfig")
local fzf_lsp = require("fzf_lsp")
local glance = require("glance")
local actions = glance.actions
local lsp_inlayhints = require("lsp-inlayhints")
if lsp_inlayhints then
	lsp_inlayhints.setup()
end
capabilities = require("lsp-selection-range").update_capabilities(capabilities)
glance.setup({
	height = 30,
	mappings = {
		list = {
			["<C-b>"] = actions.preview_scroll_win(5),
			["<C-f>"] = actions.preview_scroll_win(-5),
			["<C-]>"] = actions.jump_vsplit,
			["<C-x>"] = actions.jump_split,
			["<C-t>"] = actions.jump_tab,
			["<M-q>"] = actions.close,
			["<leader>q"] = actions.close,
			["<M-L>"] = actions.enter_win("preview"),
			["<C-l>"] = actions.enter_win("preview"),
			-- action disable
			["<leader>l"] = false,
			["<C-u>"] = false,
			["<C-d>"] = false,
			["q"] = false,
			["Q"] = false,
			["v"] = false,
			["s"] = false,
			["t"] = false,
			["o"] = false,
		},
		preview = {
			["<M-q>"] = actions.close,
			["<leader>q"] = actions.close,
			["<Tab>"] = actions.next_location,
			["<S-Tab>"] = actions.previous_location,
			["<M-H>"] = actions.enter_win("list"),
			["<C-h>"] = actions.enter_win("list"),
			-- action disable
			["Q"] = false,
			["<leader>l"] = false,
		},
	},
	list = {
		position = "left",
		width = 0.3,
	},
	-- Configure preview window options
	preview_win_opts = {
		cursorline = true,
		number = true,
		wrap = false,
	},
	border = {
		enable = true,
	},
	theme = {
		enable = true,
		mode = "auto",
	},
	winbar = {
		enable = false,
	},
})
-----------------
-- mason
-----------------
require("mason").setup({
	install_root_dir = vim.fn.expand("~/.leovim.d/mason"),
	ui = {
		icons = {
			package_installed = "✓",
			package_pending = "➜",
			package_uninstalled = "✗",
		},
	},
})
require("mason-lspconfig").setup({
	automatic_installation = true,
	ensure_installed = vim.g.lsp_installer_servers,
})
map("n", "<M-l>m", [[<Cmd>Mason<Cr>]], { noremap = true, silent = true })
map("n", "<M-l>i", [[<Cmd>LspInfo<Cr>]], { noremap = true, silent = true })
require("nvim-lightbulb").setup({
	autocmd = { enabled = true },
})
-----------------
-- attach
-----------------
vim.lsp.handlers["workspace/symbol"] = fzf_lsp.workspace_symbol_handler
vim.lsp.handlers["textDocument/codeAction"] = fzf_lsp.code_action_handler
vim.lsp.handlers["textDocument/references"] = fzf_lsp.references_handler
vim.lsp.handlers["textDocument/definition"] = fzf_lsp.definition_handler
vim.lsp.handlers["textDocument/declaration"] = fzf_lsp.declaration_handler
vim.lsp.handlers["textDocument/typeDefinition"] = fzf_lsp.type_definition_handler
vim.lsp.handlers["textDocument/implementation"] = fzf_lsp.implementation_handler
vim.lsp.handlers["textDocument/documentSymbol"] = fzf_lsp.document_symbol_handler
vim.lsp.handlers["callHierarchy/incomingCalls"] = fzf_lsp.incoming_calls_handler
vim.lsp.handlers["callHierarchy/outgoingCalls"] = fzf_lsp.outgoing_calls_handler
local on_attach = function(client, bufnr)
	local opts = { noremap = true, silent = true, buffer = bufnr }
	local caps = client.server_capabilities
	if caps.completionProvider then
		vim.bo[bufnr].omnifunc = "v:lua.vim.lsp.omnifunc"
	end
	if caps.definitionProvider then
		vim.bo[bufnr].tagfunc = "v:lua.vim.lsp.tagfunc"
	end
	map("n", "<leader>a", vim.lsp.buf.code_action, opts)
	map("x", "<leader>a", vim.lsp.buf.code_action, opts)
	-- signatureHelp
	map("i", "<C-x><C-x>", vim.lsp.buf.signature_help, opts)
	-- format
	map("n", "<C-q>", vim.lsp.buf.format, opts)
	map("x", "<C-q>", vim.lsp.buf.format, opts)
	-- rename
	map("n", "gr", vim.lsp.buf.rename, opts)
	-- codelens
	map("n", "<leader>F", vim.lsp.codelens.refresh, opts)
	map("n", "<leader>R", vim.lsp.codelens.run, opts)
	-- fzf-lsp
	map("n", "gh", [[<Cmd>FzfOutgoingCalls<Cr>]], opts)
	map("n", "gl", [[<Cmd>FzfIncomingCalls<Cr>]], opts)
	map("n", "<leader>s", [[<Cmd>Vista finder<Cr>]], opts)
	map("n", "<leader>S", [[<Cmd>FzfWorkspaceSymbols<Cr>]], opts)
	-- list workspace folder && omnifunc
	map("n", "cdL", [[<Cmd>lua vim.print(vim.lsp.buf.list_workspace_folders())<Cr>]], opts)
	-- inlayhints
	if lsp_inlayhints then
		lsp_inlayhints.on_attach(client, bufnr)
		map(
			"n",
			"<M-I>",
			[[<Cmd>lua require('lsp-inlayhints').toggle()<CR>]],
			{ noremap = true, silent = false, buffer = bufnr }
		)
	end
	-- select range
	if not require("nvim-treesitter") or not require("vim.treesitter.get_range").active[bufnr] then
		map("n", "<C-s>", [[<Cmd>lua require('lsp-selection-range').trigger()<CR>]], opts)
		map("x", "<C-s>", [[<Cmd>lua require('lsp-selection-range').expand()<CR>]], opts)
	end
	-- semantic token highlight
	if caps.semanticTokensProvider and caps.semanticTokensProvider.full then
		local augroup = vim.api.nvim_create_augroup("SemanticTokens", {})
		vim.api.nvim_create_autocmd("TextChanged", {
			group = augroup,
			buffer = bufnr,
			callback = function()
				vim.lsp.semantic_tokens.force_refresh(bufnr)
			end,
		})
		-- fire it first time on load as well
		vim.lsp.semantic_tokens.start(bufnr, client)
	end
end
-- set each lsp
for _, lsp in ipairs(require("mason-lspconfig").get_installed_servers()) do
	if lsp == "lua_ls" then
		lspconfig[lsp].setup({
			on_attach = on_attach,
			capabilities = capabilities,
			filetypes = { "lua" },
			settings = {
				Lua = {
					diagnostics = {
						globals = { "vim" },
					},
				},
			},
		})
	elseif lsp == "rust_analyzer" and Installed("rust-tools.nvim") then
		require("rust-tools").setup({
			tools = {
				runnables = {
					use_telescope = false,
				},
				inlay_hints = {
					auto = false,
					show_parameter_hints = false,
					parameter_hints_prefix = "",
					other_hints_prefix = "HINT",
				},
			},
			server = {
				on_attach = on_attach,
				capabilities = capabilities,
				filetypes = { "rust" },
				settings = {
					["rust-analyzer"] = {
						assist = {
							importMergeBehavior = "last",
							importPrefix = "by_self",
						},
						diagnostics = {
							disabled = { "unresolved-import" },
						},
						cargo = {
							allFeatures = true,
						},
						procMacro = {
							enable = true,
						},
						checkOnSave = {
							command = "clippy",
						},
					},
				},
			},
		})
	elseif lsp == "gopls" then
		lspconfig[lsp].setup({
			on_attach = on_attach,
			capabilities = capabilities,
			settings = {
				gopls = {
					analyses = {
						unusedparams = true,
					},
					staticcheck = true,
					gofumpt = true,
				},
			},
		})
	else
		lspconfig[lsp].setup({
			on_attach = on_attach,
			capabilities = capabilities,
		})
	end
end
-- border
vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, {
	border = "single",
})
vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, {
	border = "single",
	close_events = { "BufHidden", "InsertLeave" },
})
-- lint
vim.api.nvim_create_autocmd({ "BufWritePost" }, {
	callback = function()
		require("lint").try_lint()
	end,
})
-- winbar
require("winbar").setup({
	enabled = true,
	show_file_path = true,
	show_symbols = true,
	colors = {
		path = "", -- You can customize colors like #c946fd
		file_name = "",
		symbols = "",
	},
	icons = {
		file_icon_default = "",
		seperator = ">",
		editor_state = "●",
		lock_icon = "",
	},
	exclude_filetype = {
		"help",
		"startify",
		"dashboard",
		"neogitstatus",
		"netrw",
		"floaterm",
		"terminal",
		"flog",
		"fzf",
		"fugitive",
		"vim-plug",
		"qf",
	},
})
vim.api.nvim_create_autocmd("FileType", {
	pattern = {
		"fzf",
		"leaderf",
		"fern",
		"vista",
		"vista_kind",
		"vista_toc",
		"netrw",
		"vim-plug",
		"nofile",
		"floaterm",
		"coctree",
		"fzf-funky",
	},
	callback = function()
		vim.wo.winbar = ""
	end,
})
vim.api.nvim_create_autocmd({ "BufEnter", "BufRead", "BufReadPost", "BufCreate" }, {
	callback = function()
		if vim.bo.buftype == "" or vim.bo.buftype == "terminal" then
			vim.wo.winbar = ""
		end
	end,
})
